#include <iostream>
#include "ConcreteReactor.h"
using namespace std;


ConcreteReactor::ConcreteReactor(void) : freeHandleConnections(MAX_NO_OF_HANDLES)
{
	for(int i = 0; i < MAX_NO_OF_HANDLES; i++)
	{
		demuxTable.handleConnection[i].eventhandler = NULL;
	}
}


ConcreteReactor::~ConcreteReactor(void)
{
}


void ConcreteReactor::register_handler(IEventHandler<SOCKET> *eventHandler, Event_Type eventType)
{
	int position = 0;
	if(freeHandleConnections > 0)
	{
		position = nextHandler();
		demuxTable.handleConnection[position].eventhandler = eventHandler;
		demuxTable.handleConnection[position].eventType = eventType;

		--freeHandleConnections;
	}
}


void ConcreteReactor::register_handler(Handler<SOCKET> h, IEventHandler<SOCKET> *eventHandler, Event_Type eventType)
{
	register_handler(eventHandler, eventType);
}


void ConcreteReactor::remove_handler(IEventHandler<SOCKET> *eventHandler,Event_Type eventType)
{
	remove_handler(eventHandler->get_handle(),eventType);
}


void ConcreteReactor::remove_handler(Handler<SOCKET> handler, Event_Type eventType)
{
	if(freeHandleConnections > 0)
	{
		for(int i = 0; i < MAX_NO_OF_HANDLES; i++)
		{
			if(demuxTable.handleConnection[i].eventhandler != NULL)
			{
				if(demuxTable.handleConnection[i].eventhandler->get_handle() == handler && demuxTable.handleConnection[i].eventType == eventType)
				{
					demuxTable.handleConnection[i].eventhandler = NULL;
					demuxTable.handleConnection[i].eventType = NOT_DEFINED;
					++freeHandleConnections;

					break;
				}
			}
		}
	}
}


bool ConcreteReactor::handle_events(timeval* timeout)
{
	fd_set rdSet, wrSet, exSet;
	FD_ZERO(&rdSet);
	FD_ZERO(&wrSet);
	FD_ZERO(&exSet);

	demuxTable.convert_to_fd_sets(&rdSet,&wrSet,&exSet);

	//kan fjernes
	//int test = ::send(demuxTable.handleConnection[0].eventhandler->get_handle().getConnection(), "hej med dig,4",13,0);
	//test = WSAGetLastError();

	int result = synch.select(MAX_NO_OF_HANDLES-freeHandleConnections+1,&rdSet,&wrSet,&exSet,timeout);
	
	if(result > 0)
	{
		for(int i = 0; i <	MAX_NO_OF_HANDLES; i++)
		{
			if(demuxTable.handleConnection[i].eventhandler != NULL)
			{
				if(synch.isInSet(demuxTable.handleConnection[i].eventhandler->get_handle().getConnection(),&rdSet))
				{
					if(demuxTable.handleConnection[i].eventType == READ_EVENT)
						demuxTable.handleConnection[i].eventhandler->handle_event(demuxTable.handleConnection[i].eventhandler->get_handle(),READ_EVENT);
					else if(demuxTable.handleConnection[i].eventType == ACCEPT_EVENT) 
						demuxTable.handleConnection[i].eventhandler->handle_event(demuxTable.handleConnection[i].eventhandler->get_handle(),ACCEPT_EVENT);
				}

				else if(synch.isInSet(demuxTable.handleConnection[i].eventhandler->get_handle().getConnection(),&wrSet))
				{
					if(demuxTable.handleConnection[i].eventType == INIT_EVENT) 
						demuxTable.handleConnection[i].eventhandler->handle_event(demuxTable.handleConnection[i].eventhandler->get_handle(),INIT_EVENT);

					else if(demuxTable.handleConnection[i].eventType == WRITE_EVENT) 
						demuxTable.handleConnection[i].eventhandler->handle_event(demuxTable.handleConnection[i].eventhandler->get_handle(),WRITE_EVENT);

					remove_handler(demuxTable.handleConnection[i].eventhandler->get_handle(),demuxTable.handleConnection[i].eventType);
				}
			}
		}

		return true;
	}

	else if(result == 0)
	{
		return false;
	}

	else
	{
		cout << "Connection error" << endl;
		return false;
	}
}


int ConcreteReactor::nextHandler()
{
	for(int i = 0; i < MAX_NO_OF_HANDLES; i++)
	{
		if(demuxTable.handleConnection[i].eventhandler == NULL)
			return i;
	}

	return -1;
}
